home *** CD-ROM | disk | FTP | other *** search
/ MacHack 1996 / MacHack 1996.toast / Hacks / Hacks ’92 / FinderMenu ƒ / FinderMenu INIT ƒ / MenuList.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-09-10  |  12.2 KB  |  600 lines  |  [TEXT/KAHL]

  1. /*
  2.  * (C) 1992 SixxHeads Software
  3.  * (C) 1992 Berkeley Systems Inc.
  4.  * 
  5.  * This code is freely distributable, but credit must be given in any
  6.  * derivative work.
  7.  * 
  8.  * <Revision History>
  9.  *        04/28/92  smz  Created.
  10.  *      06/13/92  smz  now using fsspecs to get the info / send appleevent to FMA
  11.  * <release 1.0>
  12.  */
  13.  
  14. #include <appleevents.h>
  15. #include "Utils.h"
  16. #include "FinderMenuInterface.h"
  17. #include "MenuList.h"
  18. #include <stdlib.h>
  19. #include <string.h>
  20. #include <stddef.h>
  21. #include <OSUtils.h>
  22. #include <Memory.h>
  23.  
  24. #include "Patches.h"
  25.  
  26. typedef struct {
  27.     MenuHandle    itsHandle;
  28.     short        itsOriginalID;
  29.  
  30.     // for hier menus
  31.     short        itsBeforeID;
  32.  
  33.     Boolean        itsInstalled;
  34. } CopiedMenuRecord, **CopiedMenuHandle;
  35.  
  36. typedef struct {
  37.     OSType                  itsTag;
  38.     AppleEvent            itsEvent;
  39.     Boolean                itsIdle;
  40.     Boolean                itsUnused;
  41.     short                itsMenuCount;
  42.     CopiedMenuHandle    itsMenus;
  43. } MenuClient, **MenuClientHandle;
  44.  
  45. static MenuClientHandle theMenuClients;
  46. static short theNextSlot = 1;
  47.  
  48. #define AllocMemory(l)    NewHandleSys(l)
  49.  
  50. /***************************************************************************/
  51.  
  52. #define CountClients()    ((theMenuClients == nil)?         \
  53.                             0 :                         \
  54.                             (GetHandleSize(theMenuClients) / sizeof(MenuClient)))
  55.  
  56. static MenuClient *GetMenuClient(reg OSType creator)
  57. {
  58.     reg MenuClient *pClient;
  59.     reg short ctClients;
  60.     short i;
  61.     
  62.     if (theMenuClients == nil)
  63.         return nil;
  64.  
  65.     ctClients = CountClients();
  66.     pClient = *theMenuClients;
  67.     while (ctClients--) {
  68.         if (! pClient->itsUnused)
  69.             if (pClient->itsTag == creator)
  70.                 return pClient;
  71.         ++pClient;
  72.     }
  73.     return nil;
  74. }
  75.  
  76. static MenuClient *FindEmptyClient(void)
  77. {
  78.     reg MenuClient *pClient;
  79.     reg short ctClients;
  80.     short i;
  81.     
  82.     if (theMenuClients == nil)
  83.         return nil;
  84.  
  85.     ctClients = CountClients();
  86.     pClient = *theMenuClients;
  87.     while (ctClients--) {
  88.         if (pClient->itsUnused)
  89.             return pClient;
  90.         ++pClient;
  91.     }
  92.     return nil;
  93. }
  94.  
  95. static void DeleteCopiedMenus(MenuClient *pClient)
  96. {
  97.     reg CopiedMenuRecord *pMenu;
  98.     reg short i;
  99.     OSErr err;
  100.  
  101.     if (pClient == nil)
  102.         return;
  103.  
  104.     if (pClient->itsMenus == nil)
  105.         return;
  106.  
  107.     pMenu = *pClient->itsMenus;
  108.  
  109.     for (i = 0;  i < pClient->itsMenuCount;  i++, pMenu++) {
  110. #ifdef DEBUG
  111.         if (pMenu->itsInstalled)
  112.             DebugStr("\pdanger!  that menus installed!");
  113. #endif
  114.  
  115.         DisposeHandle(pMenu->itsHandle);
  116.     }
  117.  
  118.     pClient->itsMenuCount = 0;    
  119.     DisposeHandle(pClient->itsMenus);
  120.     pClient->itsMenus = nil;
  121. }
  122.  
  123. static void EmptyClient(MenuClient *pClient)
  124. {
  125.     DeleteCopiedMenus(pClient);
  126.     pClient->itsUnused = true;
  127.     pClient->itsTag = 0;
  128. }
  129.  
  130. /***************************************************************************/
  131.  
  132. static OSErr PtrToHandSys(void* p, Handle* dest, reg unsigned short len)
  133. {
  134.     reg Handle h = AllocMemory(len);
  135.     if (h == nil)
  136.         return MemError();
  137.     BlockMove(p, *h, len);
  138.     *dest = h;
  139.     return noErr;
  140. }
  141.  
  142. short DoInit(OSType creator)
  143. {
  144.     MenuClient newClient;
  145.     OSErr err;
  146.     Boolean needAppend = false;
  147.     reg MenuClient *pNewClient;
  148.     
  149.     if (GetMenuClient(creator) != nil)
  150.         return eIDAlreadyInstalled;
  151.  
  152.     if ((pNewClient = FindEmptyClient()) == nil) {
  153.         pNewClient = &newClient;
  154.         needAppend = true;
  155.     }
  156.     pNewClient->itsTag = creator;
  157.     pNewClient->itsMenus = nil;
  158.     pNewClient->itsMenuCount = 0;
  159.     pNewClient->itsIdle = true;
  160.     pNewClient->itsUnused = false;
  161.  
  162.     if (! needAppend)
  163.         err = noErr;
  164.     else {
  165.         if (theMenuClients == nil)
  166.             err = PtrToHandSys(pNewClient, (Handle*) &theMenuClients, sizeof(MenuClient));
  167.         else
  168.             err = PtrAndHand(pNewClient, theMenuClients, sizeof(MenuClient));
  169.     }
  170.  
  171.     if (err == noErr) {
  172.         reg short rval = theNextSlot;
  173.         theNextSlot += 64;    // REMINDSMZ: what is the maximum allowable # of menus?  of clients?
  174.         return rval;
  175.     } else {
  176.         return eOutOfMemoryError;
  177.     }
  178. }
  179.  
  180. Boolean DoAppend(OSType creator, MenuHandle hMenu, short beforeID)
  181. {
  182.     CopiedMenuRecord copiedMenu;
  183.     MenuClient *pClient;
  184.     static short negativeValue = -32000;
  185.     
  186.     HLock(theMenuClients);
  187.  
  188.     pClient = GetMenuClient(creator);
  189.  
  190.     if (pClient != nil) {    
  191.         OSErr err;
  192.  
  193.         copiedMenu.itsOriginalID = (**hMenu).menuID;
  194.         copiedMenu.itsBeforeID = beforeID;
  195.         copiedMenu.itsInstalled = false;
  196.         copiedMenu.itsHandle = (MenuHandle) CopyToSystemHeap((Handle) hMenu);
  197. #if 0
  198.         if (beforeID != -1)
  199.             (**copiedMenu.itsHandle).menuID = negativeValue++;
  200. #endif
  201.         if (copiedMenu.itsHandle != nil) {
  202.             if (pClient->itsMenus == nil)
  203.                 err = PtrToHandSys(&copiedMenu, (Handle*)&pClient->itsMenus, sizeof(copiedMenu));
  204.             else
  205.                 err = PtrAndHand(&copiedMenu, pClient->itsMenus, sizeof(copiedMenu));
  206.  
  207.             if (err == noErr)
  208.                 pClient->itsMenuCount++;
  209.         }
  210.     }
  211.  
  212.     HUnlock(theMenuClients);
  213.     
  214.     return true;
  215. }
  216.  
  217. Boolean DoDelete(OSType creator)
  218. {
  219.     if (theMenuClients == nil)
  220.         return false;
  221.  
  222.     DeleteCopiedMenus(GetMenuClient(creator));
  223.     
  224.     return true;
  225. }
  226.  
  227. Boolean DoRemove(OSType creator)
  228. {
  229.     reg MenuClient *pClient;
  230.     reg short ctClients;
  231.     short i;
  232.  
  233.     if (theMenuClients == nil)
  234.         return false;
  235.  
  236.     if (! DoDelete(creator))
  237.         return false;
  238.  
  239.     ctClients = CountClients();
  240.     pClient = *theMenuClients;
  241.     for (i = 0;  i < ctClients;  i++, pClient++) {
  242.         if ((! pClient->itsUnused) && (pClient->itsTag == creator)) {
  243.             EmptyClient(pClient);
  244.             return true;
  245.         }
  246.     }
  247.     return false;
  248. }
  249.  
  250. Boolean DoClientDone(OSType creator)
  251. {
  252.     reg MenuClient *pClient = GetMenuClient(creator);
  253.     pClient->itsIdle = true;
  254.     return false;
  255. }
  256.  
  257. /***************************************************************************/
  258.  
  259. void InsertAllMenus(Boolean forShow)
  260. {
  261.     reg MenuClient *pClient;
  262.     reg short ctClients;
  263.     reg short i;
  264.     
  265.     if (theMenuClients == nil)
  266.         return;
  267.     
  268.     HLock(theMenuClients);
  269.  
  270.     ctClients = CountClients();
  271.     pClient = *theMenuClients;
  272.     for (i = 0;  i < ctClients;  i++, pClient++) {
  273.         reg short ctMenus;
  274.         reg short j;
  275.         reg CopiedMenuRecord *pMenu;
  276.  
  277.         if (pClient->itsUnused || (pClient->itsMenus == nil))
  278.             continue;
  279.  
  280.         HLock(pClient->itsMenus);
  281.  
  282.         pMenu = *pClient->itsMenus;
  283.         for (j = 0;  j < pClient->itsMenuCount;  j++, ++pMenu) {
  284.             if (pMenu->itsInstalled)
  285.                 continue;
  286.  
  287.             if (forShow && pMenu->itsBeforeID == -1)
  288.                 continue;
  289.                 
  290.             if (pClient->itsIdle) {
  291.                 EnableItem(pMenu->itsHandle, 0);
  292.             } else {
  293.                 DisableItem(pMenu->itsHandle, 0);
  294.             }
  295.  
  296.             InsertMenu(pMenu->itsHandle, pMenu->itsBeforeID);
  297.  
  298.             pMenu->itsInstalled = true;
  299.         }
  300.  
  301.         HUnlock(pClient->itsMenus);
  302.     }
  303.  
  304.     HUnlock(theMenuClients);
  305. }
  306.  
  307. void RemoveAllMenus(Boolean forShow)
  308. {
  309.     reg MenuClient *pClient;
  310.     reg short ctClients;
  311.     reg short i;
  312.     
  313.     if (theMenuClients == nil)
  314.         return;
  315.  
  316.     HLock(theMenuClients);
  317.  
  318.     ctClients = CountClients();
  319.     pClient = *theMenuClients;
  320.     for (i = 0;  i < ctClients;  i++, ++pClient) {
  321.         reg short ctMenus;
  322.         reg short j;
  323.         reg CopiedMenuRecord *pMenu;
  324.  
  325.         if (pClient->itsUnused || pClient->itsMenus == nil)
  326.             continue;
  327.             
  328.         HLock(pClient->itsMenus);
  329.  
  330.         pMenu = *pClient->itsMenus;
  331.         for (j = 0;  j < pClient->itsMenuCount;  j++, ++pMenu) {
  332.             if (! pMenu->itsInstalled)
  333.                 continue;
  334.  
  335.             if (forShow && pMenu->itsBeforeID == -1)
  336.                 continue;
  337.  
  338.             pMenu->itsInstalled = false;
  339.             DeleteMenu(pMenu->itsOriginalID);
  340.         }
  341.  
  342.         HUnlock(pClient->itsMenus);
  343.     }
  344.  
  345.     HUnlock(theMenuClients);
  346. }
  347.  
  348. /***************************************************************************/
  349.  
  350. Boolean OwnedMenuHit(unsigned long result, OSType *creator, AEDescList *descList)
  351. {
  352.     reg MenuClient *pClient;
  353.     reg short ctClients;
  354.     reg short menuID = result >> 16;
  355.     
  356.     if (theMenuClients == nil)
  357.         return false;
  358.     
  359.     ctClients = CountClients();
  360.     pClient = *theMenuClients;
  361.  
  362.     while (ctClients--) {
  363.         reg short ctMenus;
  364.         reg short i;
  365.         reg CopiedMenuRecord *pMenu;
  366.  
  367.         if (pClient->itsUnused || (pClient->itsMenus == nil))
  368.             continue;
  369.  
  370.         pMenu = *pClient->itsMenus;
  371.  
  372.         for (i = 0;  i < pClient->itsMenuCount;  i++, ++pMenu) {
  373.             if ((**pMenu->itsHandle).menuID == menuID) {
  374.                 *creator = pClient->itsTag;
  375.                 return NewHitList(pClient->itsTag, pMenu->itsOriginalID, result & 0xffff, descList);
  376.             }
  377.         }
  378.  
  379.         ++pClient;
  380.     }
  381.     
  382.     return false;
  383. }
  384.  
  385. /***************************************************************************/
  386. #if 0
  387. pascal short waitProc(ev, sleep, mousergn)
  388.     EventRecord *ev; 
  389.     long *sleep; 
  390.     RgnHandle *mousergn;
  391. {
  392.     
  393.     return (0); /*keep waiting*/
  394. } /*IACwaitroutine*/
  395.  
  396. #endif
  397.  
  398. #if 0
  399.  
  400. //sample code for FMA
  401. \
  402. <AppleEvents.h>
  403.  
  404. pascal OSErr handleMenuHitEvent (AppleEvent *event, AppleEvent *reply, long refcon)
  405. {
  406.     AppleEvent evSend, reply2;
  407.  
  408.     AESuspendTheCurrentEvent (event);
  409.  
  410.     AEGetKeyPtr (evINIT, 'flis', &pathDesc); //gets list from INIT
  411.     
  412.     AEGetKeyDesc (evINIT, 'flis', &pathDesc); //gets list from INIT
  413.     
  414.     AEGetKeyDesc (evINIT, 'flis', &pathDesc); //gets list from INIT
  415.     
  416.     ShareMenuHit (...);
  417.     
  418.     AESetTheCurrentEvent (event); //needed?
  419.     
  420.     AEResumeTheCurrentEvent (event, reply, kAENoDispatch, refcon);
  421.     
  422.     
  423.  
  424. AEGetKeyDesc (evINIT, 'flis', &pathDesc); //gets list from INIT
  425.  
  426. err = AEPutParamDesc(reply, '----', &pathDesc); //returns list to Frontier
  427.  
  428.  
  429. void convert (MenuHitRecord *mr, AppleEvent *ev)
  430. {
  431.     AEAddressDesc adr;
  432.     OSErr err;
  433.     AEDesc pathdesc;
  434.     short i;
  435.     
  436.     err = AECreateDesc(typeApplSignature, &creator, sizeof(OSType), &adr);
  437.     
  438.     err = AECreateAppleEvent (cGetFinderMenuProc, finderMenuHitEvent, &adr, 
  439.         kAutoGenerateReturnID, kAnyTransactionID, ev);
  440.     
  441.     AEDisposeDesc (&adr);
  442.     
  443.     err = AEPutKeyPtr (ev, 'mnid', typeShortInteger, &mr->itsMenuID, sizeof (short));
  444.     
  445.     err = AEPutKeyPtr (ev, 'mnit', typeShortInteger, &mr->itsItem, sizeof (short));
  446.     
  447.     pathDesc.descriptorType = 'TEXT';
  448.     for (i = (**cachedHitHandle).itsFileCount - 1;  i >= 0 && err == noErr;  i--) {
  449.         Handle hName = (**cachedHitHandle).itsFileNames[i];
  450.         if (hName) {
  451.             pathDesc.dataHandle = hName;
  452.             err = AEPutDesc(&resultList, 0, &pathDesc);
  453.         }
  454.     }
  455.  
  456.  
  457.     if (err == noErr)
  458.         err = AEPutKeyParamDesc(ev, 'flis', &resultList);
  459.     
  460.     AEDisposeDesc (&resultList);
  461.     
  462.     /****.......*/
  463.     
  464.     AppleEvent event, reply;
  465.     
  466.     //build as above during collect sequence...
  467.     
  468.     AESend(&event, &reply, kAENoReply, kAEHighPriority, kNoTimeOut, nil, nil);
  469.     
  470.     AEDisposeDesc(&event);
  471.     
  472.     AEDisposeDesc(&reply);
  473. }
  474. #endif
  475.  
  476. void SendCancelledEvent(OSType creator)
  477. {
  478.     reg MenuClient *pClient;
  479.     AEAddressDesc adr;
  480.     AppleEvent event, reply;
  481.     OSErr err;
  482.  
  483.     err = AECreateDesc(typeApplSignature, (void*) &creator, sizeof(OSType), &adr);
  484.  
  485.     if (err != noErr)
  486.         return;
  487.  
  488.     err = AECreateAppleEvent(cGetFinderMenuProc, cFinderCancelHitEvent, &adr, 
  489.         kAutoGenerateReturnID, kAnyTransactionID, &event);
  490.  
  491.     AEDisposeDesc(&adr);
  492.  
  493.     if (err == noErr)
  494.         AESend(&event, &reply, kAENoReply, kAEHighPriority, kNoTimeOut, nil, nil);
  495.         
  496.     AEDisposeDesc(&event);
  497.     
  498.     AEDisposeDesc(&reply);
  499. }
  500.  
  501. // caller is responsible for destroying hitList!            
  502. void SendMenuHitInfo(OSType creator, AEDescList *hitList)
  503. {
  504.     reg MenuClient *pClient = GetMenuClient(creator);
  505.  
  506.     if (pClient != nil) {
  507.         AppleEvent event = pClient->itsEvent;
  508.         AppleEvent reply;
  509.         
  510.         if (event.dataHandle == nil) {
  511. #ifdef DEBUG
  512.             DebugStr("\pnil datahandle!");
  513.             return;
  514. #endif
  515.         }
  516.  
  517.         pClient->itsEvent.dataHandle = nil;    // REMINDSMZ: by way of debugging...
  518.         pClient->itsIdle = false;
  519.         
  520.         if (noErr == AEPutKeyDesc(&event, 'flis', hitList))
  521.             AESend(&event, &reply, kAENoReply, kAEHighPriority, kNoTimeOut, nil, nil);
  522.  
  523.         AEDisposeDesc(&event);
  524.  
  525.         AEDisposeDesc(&reply);
  526.     }
  527. }
  528.  
  529. // this creator's info needs to get tossed - cmd-. was hit or an error occured.
  530. void DeleteMenuHitInfo(OSType creator)
  531. {
  532.     reg MenuClient *pClient = GetMenuClient(creator);
  533.     AppleEvent event;
  534.  
  535.     if (pClient == nil)
  536.         return;
  537.  
  538.     if (pClient->itsIdle)
  539.         return;     // nothing to do
  540.     
  541.     event = pClient->itsEvent;
  542.  
  543.     pClient->itsEvent.dataHandle = nil;    // REMINDSMZ: by way of debugging...
  544.     pClient->itsIdle = false;
  545.  
  546.     if (event.dataHandle == nil) {
  547. #ifdef DEBUG
  548.         DebugStr("\pnil datahandle!?");
  549. #endif
  550.         return;
  551.     }
  552.     
  553.     AEDisposeDesc(&event);
  554. }
  555.  
  556. Boolean NewHitList(OSType creator, short menuID, short item, AEDescList *descList)
  557. {
  558.     reg MenuClient *pClient;
  559.     AEAddressDesc adr;
  560.     AppleEvent event;
  561.     OSErr err;
  562.  
  563.     err = AECreateList(nil, 0, false, descList);
  564.     
  565.     if (err != noErr)
  566.         return false;
  567.  
  568.     err = AECreateDesc(typeApplSignature, (void*) &creator, sizeof(OSType), &adr);
  569.  
  570.     if (err != noErr)
  571.         return false;
  572.  
  573.     err = AECreateAppleEvent(cGetFinderMenuProc, cFinderMenuHitEvent, &adr, 
  574.         kAutoGenerateReturnID, kAnyTransactionID, &event);
  575.  
  576.     AEDisposeDesc(&adr);
  577.  
  578.     if (err == noErr) {
  579.         err = AEPutKeyPtr(&event, 'mnid', typeShortInteger, (void*) &menuID, sizeof(short));
  580.  
  581.         if (err == noErr)
  582.             err = AEPutKeyPtr(&event, 'mnit', typeShortInteger, (void*) &item, sizeof(short));
  583.     }
  584.  
  585.     if (err != noErr) {
  586.         AEDisposeDesc(&event);
  587.         return false;
  588.     }
  589.  
  590.     pClient = GetMenuClient(creator);
  591.     
  592.     if (pClient == false) {
  593.         AEDisposeDesc(&event);
  594.         return false;
  595.     }
  596.     pClient->itsEvent = event;
  597.  
  598.     return true;
  599. }
  600.